package com.karrim.server.util.array;

import com.karrim.server.util.array.abstr.AbstractArray;
import com.karrim.server.util.array.def.DynamicArray;
import com.karrim.server.util.def.Indexable;
import java.util.Iterator;

/**
 *
 * @author andrea.cantafio
 */
public class LinkedDynamicArray<T extends Object> extends AbstractArray<T> implements DynamicArray<T>, Indexable<T, Integer> {

    private class Node {

        public Node(T content) {
            this(null, null, content);
        }

        private Node(Node previous, T content) {
            this(previous, null, content);
        }

        private Node(Node previous, Node next, T content) {
            this.previous = previous;
            this.next = next;
            this.content = content;
        }
        private T content;
        private Node previous, next;
    }

    public LinkedDynamicArray() {
    }

    @Override
    public LinkedDynamicArray add(T t) {
        Node node = new Node(last, t);
        last.next = node;
        last = node;
        size++;
        return this;
    }

    @Override
    public T get(Integer index) throws ArrayIndexOutOfBoundsException {
        if (index >= size) {
            throw new ArrayIndexOutOfBoundsException("Index MUST be smaller than array's size: found index=" + index + ", size=" + size);
        }
        Iterator<T> iterator = iterator();
        for (int i = 0; i < size; i++) {
            T t = iterator.next();
            if (i == index - 1) {
                return t;
            }
        }
        return null;
    }

    @Override
    public Integer getCapacity() {
        return Integer.MAX_VALUE;
    }

    @Override
    public Integer getSize() {
        return size;
    }

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            @Override
            public boolean hasNext() {
                return current.next != null;
            }

            @Override
            public T next() {
                current = current.next;
                return current.content;
            }

            @Override
            public void remove() {
                if (current != root) {
                    if (current != last) {
                        /* Linking previous node */
                        current.previous.next = current.next;
                        /* Linking next node */
                        if (current.next != null) {
                            current.next.previous = current.previous;
                        }
                        /* Cleaning references of current node to avoid memory leaks */
                        current.previous = current.next = null;
                        current = current.previous;
                        size--;
                    } else {
                        /* Cleaning previous node's reference */
                        last.previous.next = null;
                        /* Moving back to previous node */
                        current = last = last.previous;
                    }
                }
            }
            private Node current = root;
        };
    }
    private Node root = new Node(null), last = root;
}
